package pl.edu.kassiopeia.repository.controller;

import java.io.IOException;
import java.util.List;
import java.util.zip.ZipException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import org.xml.sax.SAXException;

import pl.edu.kassiopeia.repository.exceptions.PluginNotFoundException;
import pl.edu.kassiopeia.repository.model.Plugin;
import pl.edu.kassiopeia.repository.service.PluginJarService;
import pl.edu.kassiopeia.repository.service.PluginService;
import pl.edu.kassiopeia.repository.util.PluginDescriptorConverter;
import pl.edu.kassiopeia.repository.util.json.JsonConverter;

@Controller
public class PluginController {
	private final Logger logger = Logger.getLogger(getClass());
	
	@Autowired
	PluginService pluginService;
	
	@Autowired
	PluginJarService pluginJarService;
	
	
	public void setPluginService(PluginService pluginService){
		this.pluginService = pluginService;
	}
	
	@RequestMapping(value = "/all", method = RequestMethod.GET)
	public ModelAndView listAllPlugins() {
		logger.info("Invoked request method for all plugins list");
		JsonConverter jsonConverter = new JsonConverter();
		
		List<Plugin> pluginList = pluginService.findAll();
		
		String msg = jsonConverter.convert(pluginList);
		
        ModelAndView model = new ModelAndView("ListPluginsPage");
        model.addObject("msg", msg.toString());
        return model;
    }
	
	
	@RequestMapping(value = "/{groupId}/{pluginId}/{pluginVersion}/details", method = RequestMethod.GET)
    public ModelAndView getPluginDetails(@PathVariable("groupId") String groupId,
    		@PathVariable("pluginId") String pluginId, 
    		@PathVariable("pluginVersion") String pluginVersion,
    		HttpServletRequest request,
			HttpServletResponse response) throws PluginNotFoundException, ZipException, IOException, SAXException, ParserConfigurationException {
		logger.info("Invoked request method for plugin details with groupId: " 
				+ groupId + " pluginId: " + pluginId + " version: " + pluginVersion);
		String msg = null;
		Plugin plugin = null;
		plugin = pluginService.findByCoordinates(groupId, pluginId, pluginVersion);
		String pluginDescriptor = null;
		pluginDescriptor = pluginJarService.getPluginXml(plugin.getJarFile());
		JsonConverter jsonConverter = new JsonConverter();
		msg = jsonConverter.convert(pluginDescriptor);
		
        ModelAndView model = new ModelAndView("PluginDetailsPage");
        model.addObject("msg", msg);
        return model;
    }
	
	@RequestMapping(value = "/upload", method = RequestMethod.GET)
	public ModelAndView uploadFilePage(){
		ModelAndView model = new ModelAndView("UploadFilePage");
	    return model;
	}
	
	@RequestMapping(value = "/upload", method = RequestMethod.POST)
	public ModelAndView uploadFile(HttpServletRequest request,
			HttpServletResponse response) throws SAXException, IOException, ParserConfigurationException {
		logger.info("Requested method POST for plugin upload");
		ModelAndView model = new ModelAndView("UploadFilePage");
		String msg = "File uploaded.";
		
		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
		MultipartFile multipartFile = multipartRequest.getFile("file");
		
		byte[] f = null;
		f = multipartFile.getBytes();
		String pluginXml = null;
		try {
			pluginXml = pluginJarService.getPluginXml(f);
		} catch (ZipException e) {
			logger.error(e);
			msg = "Uploaded file is not a valid plugin";
		} catch (IOException e) {
			logger.error(e);
			msg = "Error while uploading file";
		}
		
		if(pluginXml != null){
			PluginDescriptorConverter pdConverter = null;

			try {
				pdConverter = new PluginDescriptorConverter(pluginXml);
			} catch (SAXException e) {
				logger.error("Invalid plugin.xml file", e);
				throw e;
			} catch (IOException e) {
				logger.error("Invalid plugin.xml file", e);
				throw e;
			} catch (ParserConfigurationException e) {
				logger.error("Invalid plugin.xml file", e);
				throw e;
			}

			Plugin plugin = new Plugin();
			plugin.setPluginId(pdConverter.getPluginId());
			plugin.setGroupId(pdConverter.getGroupId());
			plugin.setVersion(pdConverter.getVersion());
			plugin.setJarFile(f);
			pluginService.save(plugin);
		}

		model.addObject("msg", msg);
	    return model;
	}
	
	@RequestMapping(value = "/{groupId}/{pluginId}/{pluginVersion}/download", method = RequestMethod.GET)
	public ModelAndView getPluginData(@PathVariable("groupId") String groupId, 
			@PathVariable("pluginId") String pluginId, 
			@PathVariable("pluginVersion") String pluginVersion, 
			HttpServletRequest request,HttpServletResponse response) throws PluginNotFoundException, IOException {
		logger.info("Invoked request method for plugin download with groupId: " 
				+ groupId + " pluginId: " + pluginId + " version: " + pluginVersion);
		Plugin plugin = null;

		plugin = pluginService.findByCoordinates(groupId, pluginId, pluginVersion);

		String msg = "";
		byte[] file = plugin.getJarFile();
		
		String filename = plugin.getPluginId() + "-" + plugin.getVersion() + ".jar";
		String headerFileName = "attachment;filename=" + filename;
		response.setContentType("application/octet-stream");
		response.setHeader("Content-Disposition",
				headerFileName);
		FileCopyUtils.copy(file, response.getOutputStream());

        ModelAndView model = new ModelAndView("PluginDetailsPage");
        model.addObject("msg", msg);
        return model;
	}
	
	@RequestMapping(value = "/{groupId}/{pluginId}/{pluginVersion}/delete", method = RequestMethod.GET)
	public ModelAndView deletePluginData(@PathVariable("groupId") String groupId, 
			@PathVariable("pluginId") String pluginId, 
			@PathVariable("pluginVersion") String pluginVersion, 
			HttpServletRequest request,HttpServletResponse response) throws PluginNotFoundException, IOException {
		logger.info("Invoked request method for delete plugin with groupId: " 
				+ groupId + " pluginId: " + pluginId + " version: " + pluginVersion);
		Plugin plugin = null;

		plugin = pluginService.findByCoordinates(groupId, pluginId, pluginVersion);
		pluginService.delete(plugin);
		
		return listAllPlugins();
	}
	
	
//	@ExceptionHandler(PluginNotFoundException.class)
//	@ResponseStatus(HttpStatus.NOT_FOUND)
//	public void handleException(PluginNotFoundException ext) {}
//	
//	@ExceptionHandler(ZipException.class)
//	@ResponseStatus(HttpStatus.BAD_REQUEST)
//	public void handleException(ZipException ext) {
//		logger.error(ext);
//	}
//	
//	@ExceptionHandler(IOException.class)
//	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
//	public void handleException(IOException ext) {
//		logger.error(ext);
//	}
//	
//	@ExceptionHandler(SAXException.class)
//	@ResponseStatus(HttpStatus.BAD_REQUEST)
//	public void handleException(SAXException ext) {
//		logger.error(ext);
//	}
//	
//	@ExceptionHandler(ParserConfigurationException.class)
//	@ResponseStatus(HttpStatus.BAD_REQUEST)
//	public void handleException(ParserConfigurationException ext) {
//		logger.error(ext);
//	}
//	
//	@ExceptionHandler(DataIntegrityViolationException.class)
//	@ResponseStatus(HttpStatus.BAD_REQUEST)
//	public void handleException(DataIntegrityViolationException ext) {
//		logger.error(ext);
//	}
//	
//	@ExceptionHandler(Exception.class)
//	@ResponseStatus(HttpStatus.BAD_REQUEST)
//	public void handleException(Exception ext) {
//		logger.error(ext);
//	}

}
